home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / tcl / tclm_1_0.lha / tclm-1.0 / tclmPlay.c < prev    next >
C/C++ Source or Header  |  1993-08-16  |  17KB  |  714 lines

  1. /*-
  2.  * Copyright (c) 1993 Michael B. Durian.  All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  * 1. Redistributions of source code must retain the above copyright
  8.  *    notice, this list of conditions and the following disclaimer.
  9.  * 2. Redistributions in binary form must reproduce the above copyright
  10.  *    notice, this list of conditions and the following disclaimer in the
  11.  *    documentation and/or other materials provided with the distribution.
  12.  * 3. All advertising materials mentioning features or use of this software
  13.  *    must display the following acknowledgement:
  14.  *    This product includes software developed by Michael B. Durian.
  15.  * 4. The name of the the Author may be used to endorse or promote 
  16.  *    products derived from this software without specific prior written 
  17.  *    permission.
  18.  *
  19.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 
  20.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  21.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  
  22.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
  23.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  25.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  26.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  27.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  28.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  29.  * SUCH DAMAGE.
  30.  */
  31. /*
  32.  * tclmPlay.c,v 1.9 1993/05/07 17:45:11 durian Exp
  33.  */
  34. #ifdef MIDIPLAY
  35.  
  36. static char cvsid[] = "tclmPlay.c,v 1.9 1993/05/07 17:45:11 durian Exp";
  37.  
  38. #include <signal.h>
  39. #include <sys/ioctl.h>
  40. #include <i386/isa/midiioctl.h>
  41. #include "tclInt.h"
  42. #include "tclUnix.h"
  43. #include "mutil.h"
  44. #include "mdevice.h"
  45. #include "tclm.h"
  46. #include "tclmPlay.h"
  47.  
  48. static int now_playing = 0;
  49. static int Dev;
  50. static PlayMode Mode;
  51. static int Pipe[2];
  52.  
  53. static char *play_usage = "midiplay [bg | background] [repeat] \
  54. [tracks track_list] [reltempo tempo_scalar] mfileId";
  55. static char *record_usage = "midirecord [bg | background] [play play_mfileId \
  56. [repeat] [tracks track_list] [reltempo tempo_scalar]] record_mfileId";
  57.  
  58. void
  59. Tclm_InitPlay(interp)
  60.     Tcl_Interp *interp;
  61. {
  62.  
  63.     Tcl_CreateCommand(interp, "midiplay", Tclm_MidiPlay, NULL, NULL);
  64.     Tcl_CreateCommand(interp, "midirecord", Tclm_MidiRecord, NULL, NULL);
  65.     Tcl_CreateCommand(interp, "midistop", Tclm_MidiStop, NULL, NULL);
  66.     signal(SIGCHLD, watchdog);
  67.     signal(SIGHUP, Tclm_CatchStop);
  68. }
  69.  
  70.  
  71. int
  72. Tclm_MidiPlay(dummy, interp, argc, argv)
  73.     ClientData dummy;
  74.     Tcl_Interp *interp;
  75.     int argc;
  76.     char **argv;
  77. {
  78.     double reltempo;
  79.     MIDI_FILE *mfile;
  80.     char *mfile_name;
  81.     int *tracks;
  82.     int background;
  83.     int i;
  84.     int num_tracks;
  85.     int pid;
  86.     int repeat;
  87.     int result;
  88.     
  89.  
  90.     if (argc < 2) {
  91.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  92.             play_usage, "\"", (char *)NULL);
  93.         return (TCL_ERROR);
  94.     }
  95.  
  96.     reltempo = 1.0;
  97.     repeat = 0;
  98.     background = 0;
  99.     mfile_name = NULL;
  100.     tracks = NULL;
  101.     num_tracks = 0;
  102.  
  103.     for (i = 1; i < argc; i++) {
  104.         switch(argv[i][0]) {
  105.         case 'b':
  106.             if (strncmp(argv[i], "bg", sizeof(argv[i])) == 0 ||
  107.                 strncmp(argv[i], "background", sizeof(argv[i]))
  108.                 == 0)
  109.                 background = 1;
  110.             else if (mfile_name == NULL)
  111.                 mfile_name = argv[i];
  112.             else {
  113.                 Tcl_AppendResult(interp, "bad option: ",
  114.                     "should be \"", play_usage, "\"",
  115.                     (char *)NULL);
  116.                 if (tracks != NULL)
  117.                     free(tracks);
  118.                 return (TCL_ERROR);
  119.             }
  120.             break;
  121.         case 'r':
  122.             if (strncmp(argv[i], "reltempo", strlen(argv[i]))
  123.                 == 0)
  124.                 reltempo = atof(argv[++i]);
  125.             else if (strncmp(argv[i], "repeat", strlen(argv[i]))
  126.                 == 0)
  127.                 repeat = 1;
  128.             else if (mfile_name == NULL)
  129.                 mfile_name = argv[i];
  130.             else {
  131.                 Tcl_AppendResult(interp, "bad option: ",
  132.                     "should be \"", play_usage, "\"",
  133.                     (char *)NULL);
  134.                 if (tracks != NULL)
  135.                     free(tracks);
  136.                 return (TCL_ERROR);
  137.             }
  138.  
  139.             break;
  140.         case 't':
  141.             if (strncmp(argv[i], "tracks", strlen(argv[i]))
  142.                 == 0) {
  143.                 if ((num_tracks = Tclm_ParseTracks(interp,
  144.                     argv[i + 1], &tracks)) == -1)
  145.                     return (TCL_ERROR);
  146.                 i++;
  147.             } else if (mfile_name == NULL) {
  148.                 mfile_name = argv[i];
  149.             } else {
  150.                 Tcl_AppendResult(interp, "bad option: ",
  151.                     "should be \"", play_usage, "\"",
  152.                     (char *)NULL);
  153.                 if (tracks != NULL)
  154.                     free(tracks);
  155.                 return (TCL_ERROR);
  156.             }
  157.             break;
  158.         default:
  159.             if (mfile_name == NULL)
  160.                 mfile_name = argv[i];
  161.             else {
  162.                 Tcl_AppendResult(interp, "bad option: ",
  163.                     "should be \"", play_usage, "\"",
  164.                     (char *)NULL);
  165.                 if (tracks != NULL)
  166.                     free(tracks);
  167.                 return (TCL_ERROR);
  168.             }
  169.         }
  170.     }
  171.  
  172.     if ((result = Tclm_GetMFile(interp, mfile_name, &mfile)) != TCL_OK) {
  173.         if (tracks != NULL)
  174.             free(tracks);
  175.         return (result);
  176.     }
  177.  
  178.     /* If track list isn't set use all tracks */
  179.     if (num_tracks == 0) {
  180.         num_tracks = mfile->hchunk.num_trks;
  181.         if ((tracks = (int *)malloc(sizeof(int) * num_tracks))
  182.             == NULL) {
  183.             Tcl_AppendResult(interp, "Not enough memory",
  184.                 (char *)NULL);
  185.             return (TCL_ERROR);
  186.         }
  187.         for (i = 0; i < num_tracks; i++)
  188.             tracks[i] = i;
  189.     }
  190.  
  191.     Mode = PLAY;
  192.     if ((Dev = open_midi_device(Mode)) == -1) {
  193.         Tcl_AppendResult(interp, MidiError, (char *)NULL);
  194.         free(tracks);
  195.         return (TCL_ERROR);
  196.     }
  197.  
  198.     if (!init_midi_device(Dev, &mfile->hchunk, reltempo)) {
  199.         Tcl_AppendResult(interp, MidiError, (char *)NULL);
  200.         free(tracks);
  201.         return (TCL_ERROR);
  202.     }
  203.  
  204.     if (!start_midi_device(Dev, Mode)) {
  205.         Tcl_AppendResult(interp, MidiError, (char *)NULL);
  206.         free(tracks);
  207.         return (TCL_ERROR);
  208.     }
  209.  
  210.     if (!background) {
  211.         now_playing = 1;
  212.         if (!play_tracks(Dev, mfile->tchunks, tracks, num_tracks,
  213.             repeat)) {
  214.             Tcl_AppendResult(interp, "Couldn't play tracks\n",
  215.                 MidiError, (char *)NULL);
  216.             free(tracks);
  217.             return (TCL_ERROR);
  218.         }
  219.         now_playing = 0;
  220.         if (!stop_midi_device(Dev, Mode)) {
  221.             Tcl_AppendResult(interp, MidiError, (char *)NULL);
  222.             free(tracks);
  223.             return (TCL_ERROR);
  224.         }
  225.  
  226.         /*
  227.          * give time for the stop to take effect
  228.          * since stop might not happen until next clock
  229.          */
  230.          sleep(1);
  231.  
  232.         if (!close_midi_device(Dev)) {
  233.             Tcl_AppendResult(interp, MidiError, (char *)NULL);
  234.             free(tracks);
  235.             return (TCL_ERROR);
  236.         }
  237.         Tcl_AppendResult(interp, "0", (char *)NULL);
  238.     } else {
  239.         switch(pid = fork()) {
  240.         case -1:
  241.             Tcl_AppendResult(interp, "Couldn't fork",
  242.                 (char *)NULL);
  243.             free(tracks);
  244.             return (TCL_ERROR);
  245.         case 0:
  246.             /* child */
  247.             now_playing = 1;
  248.             if (!play_tracks(Dev, mfile->tchunks, tracks,
  249.                 num_tracks, repeat)) {
  250.                 Tcl_AppendResult(interp,
  251.                     "Couldn't play tracks\n", MidiError,
  252.                     (char *)NULL);
  253.                 free(tracks);
  254.                 return (TCL_ERROR);
  255.             }
  256.             now_playing = 0;
  257.             if (!stop_midi_device(Dev, Mode)) {
  258.                 Tcl_AppendResult(interp, MidiError,
  259.                     (char *)NULL);
  260.                 free(tracks);
  261.                 return (TCL_ERROR);
  262.             }
  263.  
  264.             /*
  265.              * give time for the stop to take effect
  266.              * since stop might not happen until next clock
  267.              */
  268.              sleep(1);
  269.  
  270.             if (!close_midi_device(Dev)) {
  271.                 Tcl_AppendResult(interp, MidiError,
  272.                     (char *)NULL);
  273.                 free(tracks);
  274.                 return (TCL_ERROR);
  275.             }
  276.             exit(0);
  277.         default:
  278.             if (!close_midi_device(Dev)) {
  279.                 Tcl_AppendResult(interp, MidiError,
  280.                     (char *)NULL);
  281.                 free(tracks);
  282.                 return (TCL_ERROR);
  283.             }
  284.             sprintf(interp->result, "%d", pid);
  285.             break;
  286.         }
  287.     }
  288.  
  289.     free(tracks);
  290.     return (TCL_OK);
  291. }
  292.  
  293. int
  294. Tclm_MidiRecord(dummy, interp, argc, argv)
  295.     ClientData dummy;
  296.     Tcl_Interp *interp;
  297.     int argc;
  298.     char **argv;
  299. {
  300.     double reltempo;
  301.     MIDI_FILE *pfile;
  302.     MIDI_FILE *rfile;
  303.     TCHUNK *play_tracks;
  304.     TCHUNK *tmp_track;
  305.     char *pfile_name;
  306.     char *rfile_name;
  307.     int *tracks;
  308.     int background;
  309.     int i;
  310.     int num_tracks;
  311.     int pid;
  312.     int repeat;
  313.     int result;
  314.     
  315.  
  316.     if (argc < 2) {
  317.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  318.             record_usage, "\"", (char *)NULL);
  319.         return (TCL_ERROR);
  320.     }
  321.  
  322.     reltempo = 1.0;
  323.     repeat = 0;
  324.     background = 0;
  325.     pfile = NULL;
  326.     rfile = NULL;
  327.     pfile_name = NULL;
  328.     rfile_name = NULL;
  329.     tracks = NULL;
  330.     num_tracks = 0;
  331.  
  332.     for (i = 1; i < argc; i++) {
  333.         switch(argv[i][0]) {
  334.         case 'b':
  335.             if (strncmp(argv[i], "bg", sizeof(argv[i])) == 0 ||
  336.                 strncmp(argv[i], "background", sizeof(argv[i]))
  337.                 == 0)
  338.                 background = 1;
  339.             else if (rfile_name == NULL)
  340.                 rfile_name = argv[i];
  341.             else {
  342.                 Tcl_AppendResult(interp, "bad option: ",
  343.                     "should be \"", record_usage, "\"",
  344.                     (char *)NULL);
  345.                 if (tracks != NULL)
  346.                     free(tracks);
  347.                 return (TCL_ERROR);
  348.             }
  349.             break;
  350.         case 'p':
  351.             if (strncmp(argv[i], "play", sizeof(argv[i])) == 0)
  352.                 pfile_name = argv[++i];
  353.             else if (rfile_name == NULL)
  354.                 rfile_name = argv[i];
  355.             else {
  356.                 Tcl_AppendResult(interp, "bad option: ",
  357.                     "should be \"", record_usage, "\"",
  358.                     (char *)NULL);
  359.                 if (tracks != NULL)
  360.                     free(tracks);
  361.                 return (TCL_ERROR);
  362.             }
  363.             break;
  364.         case 'r':
  365.             if (strncmp(argv[i], "reltempo", strlen(argv[i]))
  366.                 == 0)
  367.                 reltempo = atof(argv[++i]);
  368.             else if (strncmp(argv[i], "repeat", strlen(argv[i]))
  369.                 == 0)
  370.                 repeat = 1;
  371.             else if (rfile_name == NULL)
  372.                 rfile_name = argv[i];
  373.             else {
  374.                 Tcl_AppendResult(interp, "bad option: ",
  375.                     "should be \"", record_usage, "\"",
  376.                     (char *)NULL);
  377.                 if (tracks != NULL)
  378.                     free(tracks);
  379.                 return (TCL_ERROR);
  380.             }
  381.  
  382.             break;
  383.         case 't':
  384.             if (strncmp(argv[i], "tracks", strlen(argv[i]))
  385.                 == 0) {
  386.                 if ((num_tracks = Tclm_ParseTracks(interp,
  387.                     argv[i + 1], &tracks)) == -1)
  388.                     return (TCL_ERROR);
  389.                 i++;
  390.             } else if (rfile_name == NULL) {
  391.                 rfile_name = argv[i];
  392.             } else {
  393.                 Tcl_AppendResult(interp, "bad option: ",
  394.                     "should be \"", record_usage, "\"",
  395.                     (char *)NULL);
  396.                 if (tracks != NULL)
  397.                     free(tracks);
  398.                 return (TCL_ERROR);
  399.             }
  400.             break;
  401.         default:
  402.             if (rfile_name == NULL)
  403.                 rfile_name = argv[i];
  404.             else {
  405.                 Tcl_AppendResult(interp, "bad option: ",
  406.                     "should be \"", record_usage, "\"",
  407.                     (char *)NULL);
  408.                 if (tracks != NULL)
  409.                     free(tracks);
  410.                 return (TCL_ERROR);
  411.             }
  412.         }
  413.     }
  414.  
  415.     if (rfile_name == NULL) {
  416.         Tcl_AppendResult(interp, "Must specify rfile", (char *)NULL);
  417.         if (tracks != NULL)
  418.             free(tracks);
  419.         return (TCL_ERROR);
  420.     } else {
  421.         if ((result = Tclm_GetMFile(interp, rfile_name, &rfile))
  422.             != TCL_OK) {
  423.             if (tracks != NULL)
  424.                 free(tracks);
  425.             return (result);
  426.         }
  427.     }
  428.  
  429.  
  430.     if (pfile_name == NULL)
  431.         play_tracks = NULL;
  432.     else {
  433.         if ((result = Tclm_GetMFile(interp, pfile_name, &pfile)) !=
  434.             TCL_OK) {
  435.             if (tracks != NULL)
  436.                 free(tracks);
  437.             return (result);
  438.         }
  439.         play_tracks = pfile->tchunks;
  440.     }
  441.  
  442.     /* If track list isn't set use all tracks */
  443.     if (pfile != NULL && num_tracks == 0) {
  444.         num_tracks = pfile->hchunk.num_trks;
  445.         if ((tracks = (int *)malloc(sizeof(int) * num_tracks))
  446.             == NULL) {
  447.             Tcl_AppendResult(interp, "Not enough memory",
  448.                 (char *)NULL);
  449.             return (TCL_ERROR);
  450.         }
  451.         for (i = 0; i < num_tracks; i++)
  452.             tracks[i] = i;
  453.     }
  454.     if (pfile != NULL)
  455.         Mode = PLAYRECORD;
  456.     else {
  457.         num_tracks = 0;
  458.         Mode = RECORD;
  459.     }
  460.  
  461.     if ((Dev = open_midi_device(Mode)) == -1) {
  462.         Tcl_AppendResult(interp, MidiError, (char *)NULL);
  463.         if (tracks != NULL)
  464.             free(tracks);
  465.         return (TCL_ERROR);
  466.     }
  467.  
  468.     if (!init_midi_device(Dev, &rfile->hchunk, reltempo)) {
  469.         Tcl_AppendResult(interp, MidiError, (char *)NULL);
  470.         if (tracks != NULL)
  471.             free(tracks);
  472.         return (TCL_ERROR);
  473.     }
  474.  
  475.     if (!start_midi_device(Dev, Mode)) {
  476.         Tcl_AppendResult(interp, MidiError, (char *)NULL);
  477.         if (tracks != NULL)
  478.             free(tracks);
  479.         return (TCL_ERROR);
  480.     }
  481.  
  482.     if (!background) {
  483.         now_playing = 1;
  484.         if (!record_tracks(Dev, play_tracks, tracks, num_tracks,
  485.             &rfile->tchunks[0], repeat)) {
  486.             Tcl_AppendResult(interp, "Couldn't record track\n",
  487.                 MidiError, (char *)NULL);
  488.             if (tracks != NULL)
  489.                 free(tracks);
  490.             return (TCL_ERROR);
  491.         }
  492.         now_playing = 0;
  493.         if (!stop_midi_device(Dev, Mode)) {
  494.             Tcl_AppendResult(interp, MidiError, (char *)NULL);
  495.             if (tracks != NULL)
  496.                 free(tracks);
  497.             return (TCL_ERROR);
  498.         }
  499.  
  500.         /*
  501.          * give time for the stop to take effect
  502.          * since stop might not happen until next clock
  503.          */
  504.          sleep(1);
  505.  
  506.         if (!close_midi_device(Dev)) {
  507.             Tcl_AppendResult(interp, MidiError, (char *)NULL);
  508.             if (tracks != NULL)
  509.                 free(tracks);
  510.             return (TCL_ERROR);
  511.         }
  512.         Tcl_AppendResult(interp, "0", (char *)NULL);
  513.     } else {
  514.         if (pipe(Pipe) == -1) {
  515.             Tcl_AppendResult(interp, "Couldn't open pipe: ",
  516.                 sys_errlist[errno]);
  517.             if (tracks != NULL)
  518.                 free(tracks);
  519.             return (TCL_ERROR);
  520.         }
  521.         switch(pid = fork()) {
  522.         case -1:
  523.             Tcl_AppendResult(interp, "Couldn't fork",
  524.                 (char *)NULL);
  525.             if (tracks != NULL)
  526.                 free(tracks);
  527.             return (TCL_ERROR);
  528.         case 0:
  529.             /* child */
  530.             close(Pipe[0]);
  531.             now_playing = 1;
  532.             if (!record_tracks(Dev, play_tracks, tracks,
  533.                 num_tracks, &rfile->tchunks[0], repeat))
  534.                 exit(1);
  535.             now_playing = 0;
  536.             if (!stop_midi_device(Dev, Mode))
  537.                 exit(1);
  538.  
  539.             /*
  540.              * give time for the stop to take effect
  541.              * since stop might not happen until next clock
  542.              */
  543.              sleep(1);
  544.  
  545.             if (!close_midi_device(Dev))
  546.                 exit(1);
  547.             /*
  548.              * write new track back to parent
  549.              */
  550.             if (mwrite(Pipe[1], (char *)&rfile->tchunks[0].length,
  551.                 sizeof(rfile->tchunks[0].length)) !=
  552.                 sizeof(rfile->tchunks[0].length))
  553.                 exit(1);
  554.             if (mwrite(Pipe[1],
  555.                 (char *)rfile->tchunks[0].event_start,
  556.                 rfile->tchunks[0].length) !=
  557.                 rfile->tchunks[0].length)
  558.                 exit(1);
  559.             close(Pipe[1]);
  560.             free(tmp_track);
  561.             exit(0);
  562.         default:
  563.             close(Pipe[1]);
  564.             if (!close_midi_device(Dev)) {
  565.                 Tcl_AppendResult(interp, MidiError,
  566.                     (char *)NULL);
  567.                 if (tracks != NULL)
  568.                     free(tracks);
  569.                 return (TCL_ERROR);
  570.             }
  571.             sprintf(interp->result, "%d", pid);
  572.             break;
  573.         }
  574.     }
  575.  
  576.     if (tracks != NULL)
  577.         free(tracks);
  578.     return (TCL_OK);
  579. }
  580.  
  581. void
  582. watchdog()
  583. {
  584. #ifdef UNION_WAIT
  585.     union wait wstatus;
  586. #else
  587.     int wstatus;
  588. #endif
  589.  
  590.     (void)wait(&wstatus);
  591. }
  592.  
  593. int
  594. Tclm_ParseTracks(interp, list, tracks)
  595.     Tcl_Interp *interp;
  596.     char *list;
  597.     int **tracks;
  598. {
  599.     char **track_strs;
  600.     char *chk_ptr;
  601.     int i;
  602.     int num_tracks;
  603.  
  604.     if (Tcl_SplitList(interp, list, &num_tracks, &track_strs) != TCL_OK) {
  605.         Tcl_AppendResult(interp, "Bad track list", (char *)NULL);
  606.         return (-1);
  607.     }
  608.     if ((*tracks = (int *)malloc(sizeof(int) * num_tracks)) == NULL) {
  609.         Tcl_AppendResult(interp, "No more memory", (char *)NULL);
  610.         return (-1);
  611.     }
  612.     for (i = 0; i < num_tracks; i++) {
  613.         (*tracks)[i] = (int)strtol(track_strs[i], &chk_ptr, 0);
  614.         if (chk_ptr == track_strs[i]) {
  615.             Tcl_AppendResult(interp, "Bad track value ",
  616.                 track_strs[i], (char *)NULL);
  617.             free(*tracks);
  618.             return (-1);
  619.         }
  620.     }
  621.     free((char *)track_strs);
  622.     return (num_tracks);
  623. }
  624.  
  625. int
  626. Tclm_MidiStop(dummy, interp, argc, argv)
  627.     ClientData dummy;
  628.     Tcl_Interp *interp;
  629.     int argc;
  630.     char **argv;
  631. {
  632.     MIDI_FILE *rfile;
  633.     char *chk_ptr;
  634.     unsigned char *events;
  635.     long length;
  636.     int pid;
  637.     int result;
  638.  
  639.     /*
  640.      * argv[0] - midistop
  641.      * argv[1] - pid
  642.      * argv[2] - [rfile]
  643.      */
  644.     if (argc < 2 || argc > 3) {
  645.         Tcl_AppendResult(interp, "wrong # args: should be\"",
  646.             argv[0], " pid [rfile]\"", (char *)NULL);
  647.         return (TCL_ERROR);
  648.     }
  649.  
  650.     pid = (int)strtol(argv[1], &chk_ptr, 0);
  651.     if (chk_ptr == argv[1] || pid <= 0) {
  652.         Tcl_AppendResult(interp, "bad pid value: ", argv[1],
  653.             (char *)NULL);
  654.         return (TCL_ERROR);
  655.     }
  656.     if (kill(pid, SIGHUP) != -1)
  657.         Tcl_AppendResult(interp, "1", (char *)NULL);
  658.     else {
  659.         if (errno == ESRCH)
  660.             Tcl_AppendResult(interp, "0", (char *)NULL);
  661.         else {
  662.             Tcl_AppendResult(interp, "Error killing process: ",
  663.                 sys_errlist[errno], (char *)NULL);
  664.             return (TCL_ERROR);
  665.         }
  666.     }
  667.     /* pick up recorded file if specified */
  668.     if (argc == 3) {
  669.         if ((result = Tclm_GetMFile(interp, argv[2], &rfile))
  670.             != TCL_OK)
  671.             return (result);
  672.         if (mread(Pipe[0], (char *)&length, sizeof(length)) !=
  673.             sizeof(length)) {
  674.             Tcl_AppendResult(interp, "Couldn't read rfile: ",
  675.                 sys_errlist[errno]);
  676.             close(Pipe[0]);
  677.             return (TCL_ERROR);
  678.         }
  679.         if ((events = (unsigned char *) malloc(length)) == NULL) {
  680.             Tcl_AppendResult(interp, "Not enough memory ",
  681.                 "for record file", (char *)NULL);
  682.             close(Pipe[0]);
  683.             return (TCL_ERROR);
  684.         }
  685.         if (mread(Pipe[0], (char *)events, length) != length) {
  686.             Tcl_AppendResult(interp, "Couldn't read record ",
  687.                 "track: ", sys_errlist[errno], (char *)NULL);
  688.             close(Pipe[0]);
  689.             free(events);
  690.             return (TCL_ERROR);
  691.         }
  692.         if (!put_smf_event(&rfile->tchunks[0], events, length)) {
  693.             Tcl_AppendResult(interp, "Couldn't add to ",
  694.                 "record track: ", MidiError, (char *)NULL);
  695.             close(Pipe[0]);
  696.             free(events);
  697.             return (TCL_ERROR);
  698.         }
  699.         free(events);
  700.         close(Pipe[0]);
  701.     }
  702.  
  703.     return (TCL_OK);
  704. }
  705.  
  706. void
  707. Tclm_CatchStop()
  708. {
  709.     int ret;
  710.  
  711.     ret = stop_processing(Dev);
  712. }
  713. #endif
  714.